//  IDVI 1.0 source copyright 1996 Garth A. Dickie
//
//  This source is free for non-commercial use.  No warranty, etc.
//  Please acknowledge reuse by including the line:
//
//  "Based in part on IDVI 1.0 source copyright 1996 Garth A. Dickie"
//
//  in your documentation and source code.  For commercial use or
//  distribution, please contact the author.  Please also send
//  questions, comments, bug reports, or fixes.
//
//  Best Regards,
//  Garth A. Dickie
//  dickie@elastic.avid.com

package ibook.v10.util;

//  ReadWriteLock provides synchronization methods which prevent
//  an object from having more than one writer, or both a writer and
//  a reader, simultaneously.  The writer calls getWriter before it
//  modifies the protected object, and putWriter when done.  The reader
//  calls getReader before reading the protected object, and putReader
//  when done.
//
//  The implementation is not optimal, in the sense that all waiting
//  readers and writers are notified when a writer is done; a better
//  solution would notify either one waiting writer or all waiting
//  readers.  Such an implementation would be similar to ReadWriteWaitLock,
//  but not as complicated; two queues would be maintained, with either
//  a single writer or all readers being awoken as appropriate.

public class ReadWriteLock {
    private boolean     hasWriter = false;
    private int         readerCount = 0;

    //  A writer would like access.  Wait until there is
    //  no other writer, and also no readers.

    public synchronized void getWriter( ) {
        while( hasWriter || readerCount != 0 )
            try {
                wait( );
            } catch( InterruptedException e ) {
            }
        
        hasWriter = true;
    }

    //  A writer is done writing.  Notify all waiting
    //  threads.  If there are no writers waiting, then
    //  this is optimal, since all readers wake up and
    //  obtain the lock.  If there are writers waiting,
    //  then some threads may be woken only to immediately
    //  block again.

    public synchronized void putWriter( ) {
        hasWriter = false;

        notifyAll( );
    }

    //  A reader would like access.  Wait until there is no
    //  writer.  Keep track of the number of readers.

    public synchronized void getReader( ) {
        while( hasWriter )
            try {
                wait( );
            } catch( InterruptedException e ) {
            }
        
        readerCount ++;
    }

    //  A reader is done reading.  If there are no more readers,
    //  notify a single writer (or do nothing if there are no
    //  writers waiting).

    public synchronized void putReader( ) {
        readerCount --;

        if( readerCount == 0 )
            notify( );
    }
}
